package Xml;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.*;

import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.w3c.dom.Node;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;

import java.io.File;
import java.io.IOException;

/**
 * Created with IntelliJ IDEA.
 * User: user
 * Date: 25.11.13
 * Time: 11:48
 * To change this template use File | Settings | File Templates.
 */
public class XmlSessionWriter {
    String userLogin;
    int[] levelArray;
    int pausedLevel;
    int savedPoints;
    String[] savedAnswers;
    Document document;
    String filePath = "D:\\Java\\LegasyTest\\src\\Xml\\UserSessions.xml";
    XPath xpath;

    public XmlSessionWriter(String userLogin) throws IOException, SAXException, ParserConfigurationException {
        this.userLogin = userLogin;
        this.loadDocument();
    }

    /**
     * Метод для записи сессии в XML файл.
     * @param levelArray
     * @param pausedLevel
     * @param savedPoints
     * @param savedAnswers
     * @throws XPathExpressionException
     * @throws TransformerException
     */
    public void writeSessionToXmlFile(int[] levelArray, int pausedLevel, int savedPoints, String[]
            savedAnswers) throws XPathExpressionException, TransformerException {
        this.levelArray = levelArray;
        this.pausedLevel = pausedLevel;
        this.savedPoints = savedPoints;
        this.savedAnswers = savedAnswers;
        if (isUserSessionExist()) {
            rewriteUserSession();
        } else {
        createNewUserSession();
        }
    }

    /**
     * Метод создает новый узел userSession и заполняет его.
     * @throws TransformerException
     */
    private void createNewUserSession() throws TransformerException {
        Node root = document.getFirstChild();
        Element userSession = document.createElement("userSession");
        Element login = document.createElement("login");
        Element levelArray = document.createElement("levelArray");
        Element pausedLevel = document.createElement("pausedLevel");
        Element savedPoints = document.createElement("savedPoints");
        Element savedAnswers = document.createElement("savedAnswers");
        login.appendChild(document.createTextNode(userLogin));
        levelArray.appendChild(document.createTextNode(intArrToString(this.levelArray)));
        pausedLevel.appendChild(document.createTextNode(String.valueOf(this.pausedLevel)));
        savedPoints.appendChild(document.createTextNode(String.valueOf(this.savedPoints)));
        savedAnswers.appendChild(document.createTextNode(stringArrToString(this.savedAnswers)));
        userSession.appendChild(login);
        userSession.appendChild(levelArray);
        userSession.appendChild(pausedLevel);
        userSession.appendChild(savedPoints);
        userSession.appendChild(savedAnswers);
        root.appendChild(userSession);
        transformDocument();
    }

    /**
     * Метод переопределяет значения узла userSession(когда юзер уже есть в документе и надо поменять значения сессии).
     * @throws XPathExpressionException
     * @throws TransformerException
     */
    private void rewriteUserSession() throws XPathExpressionException, TransformerException {
        XPathFactory factory = XPathFactory.newInstance();
        xpath = factory.newXPath();
        rewriteLevelArray();
        rewritePausedLevel();
        rewriteSavedPoints();
        rewriteSavedAnswers();
        transformDocument();
    }

    private void rewriteLevelArray() throws XPathExpressionException {
        String query = "//userSession[login=" + "'" + userLogin + "'" + "]/levelArray/text()";
        XPathExpression expr = xpath.compile(query);
        Object result = expr.evaluate(document, XPathConstants.NODESET);
        NodeList nodeList = (NodeList)result;
        nodeList.item(0).setTextContent(intArrToString(this.levelArray));
    }

    private void rewritePausedLevel() throws XPathExpressionException {
        String query = "//userSession[login=" + "'" + userLogin + "'" + "]/pausedLevel/text()";
        XPathExpression expr = xpath.compile(query);
        Object result = expr.evaluate(document, XPathConstants.NODESET);
        NodeList nodeList = (NodeList)result;
        nodeList.item(0).setTextContent(String.valueOf(this.pausedLevel));
    }

    private void rewriteSavedPoints() throws XPathExpressionException {
        String query = "//userSession[login=" + "'" + userLogin + "'" + "]/savedPoints/text()";
        XPathExpression expr = xpath.compile(query);
        Object result = expr.evaluate(document, XPathConstants.NODESET);
        NodeList nodeList = (NodeList)result;
        nodeList.item(0).setTextContent(String.valueOf(this.savedPoints));
    }

    private void rewriteSavedAnswers() throws XPathExpressionException {
        String query = "//userSession[login=" + "'" + userLogin + "'" + "]/savedAnswers/text()";
        XPathExpression expr = xpath.compile(query);
        Object result = expr.evaluate(document, XPathConstants.NODESET);
        NodeList nodeList = (NodeList)result;
        nodeList.item(0).setTextContent(stringArrToString(this.savedAnswers));
    }

    private void transformDocument() throws TransformerException {
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        transformer.setOutputProperty(OutputKeys.METHOD, "xml");
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        DOMSource domSource = new DOMSource(document);
        StreamResult streamResult = new StreamResult(new File(filePath));
        transformer.transform(domSource, streamResult);
    }

    /**
     * Проверяет наличие сессии с данным логином.
     * @return
     * @throws XPathExpressionException
     */
    private boolean isUserSessionExist() throws XPathExpressionException {
        boolean isExist = false;
        NodeList allUsers = document.getElementsByTagName("login");
        for (int i = 0; i < allUsers.getLength();i++){
            Node node = allUsers.item(i);
            Element userLoginNode = (Element)node;
            if (userLogin.equals(userLoginNode.getTextContent())) {
                isExist = true;
                break;
            }
        }
        return isExist;
    }

    private String intArrToString(int[] arr) {
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0;i < arr.length; i++) {
            stringBuilder.append(arr[i]);
            stringBuilder.append(",");
        }
        return stringBuilder.toString();
    }

    private String stringArrToString(String[] arr) {
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0;i < arr.length; i++) {
            stringBuilder.append(arr[i]);
            stringBuilder.append(",");
        }
        return stringBuilder.toString();
    }

    private void loadDocument() throws ParserConfigurationException, IOException, SAXException {
        File xmlFile = new File(filePath);
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
        document = documentBuilder.parse(xmlFile);
        document.getDocumentElement().normalize();
    }
}
